package spindles.gwt.client;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import spindles.gwt.shared.SettingsDTO;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class SettingsPanel extends RightPanel implements ClickListener, ChangeListener, ProgressHandler{
	
	private TextBox exportDir;
	private RadioButton raw;
	private TextBox plotHeight;
	private TextBox plotWidth;
	
	private ListBox groups;
	
	private ProgressBarHelper progressHelper = new ProgressBarHelper(this, 
			"Calculating spindle indications...",
			true);
	
	public SettingsPanel(){		
		init(new Toolbar("Settings"), createMainPanel());
		progressHelper.checkProgress();
		progressHelper.initPollTimer();
	}
	
	private VerticalPanel namePanel(String name){
		VerticalPanel namePanel = new VerticalPanel();
		Label settingName = new Label(name);	
		
		namePanel.add(new Label(""));
		namePanel.add(settingName);
		namePanel.add(new Label(""));
		namePanel.setSpacing(4);
		namePanel.setWidth("400px");
		
		return namePanel;
	}
	
	private VerticalPanel createMainPanel(){
		VerticalPanel mainPanel = new VerticalPanel();
		mainPanel.add(exportSettings());
		mainPanel.add(plotsSettings());
		mainPanel.add(thresholdSettings());
		mainPanel.add(buttonsPanel());
		
		mainPanel.setBorderWidth(1);		
		mainPanel.setWidth("100%");		
		
		return mainPanel;
	}
	
	private DockPanel buttonsPanel(){		
		DockPanel panel = new DockPanel();		
				
		Button cancel = new Button("Cancel");
		cancel.addClickListener(this);
		Button save = new Button("Save Changes");
		save.addClickListener(this);
		
		panel.add(cancel, DockPanel.WEST);
		panel.setCellHorizontalAlignment(cancel, HorizontalPanel.ALIGN_RIGHT);
		panel.add(save, DockPanel.CENTER);
		panel.setCellHorizontalAlignment(save, HorizontalPanel.ALIGN_LEFT);
		panel.setSpacing(6);
		panel.setWidth("100%");
		
		return panel;
	}
	
	private DockPanel exportSettings(){
		DockPanel panel = new DockPanel();		
		
		VerticalPanel widgetsPanel = new VerticalPanel();
		
		Label pathLbl = new Label("Default export directory: ");
		exportDir = new TextBox();
		exportDir.setText(Registry.getSettings().getExportDirectory());
		DOM.setElementProperty(exportDir.getElement(), "size", "70");
		
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(pathLbl);		
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(exportDir);		
		widgetsPanel.add(new Label(""));
		widgetsPanel.setSpacing(4);
		
		panel.add(namePanel("Export: "), DockPanel.WEST);
		panel.add(widgetsPanel, DockPanel.CENTER);
		panel.setCellHorizontalAlignment(widgetsPanel, DockPanel.ALIGN_LEFT);		
			
		return panel;
	}
	
	private Grid plotsSettings(){
		Grid panel = new Grid(1, 2);		
		
		VerticalPanel widgetsPanel = new VerticalPanel();
		
		raw = new RadioButton("raw", "Show only raw data");	
		raw.setChecked(Registry.getSettings().isShowOnlyRawData());
		RadioButton notRaw = new RadioButton("raw", "Show raw & filtered data");
		notRaw.setChecked(!Registry.getSettings().isShowOnlyRawData());
		
		HorizontalPanel heightPanel = new HorizontalPanel();
		Label heightLbl = new Label("Plot Height (in pixels): ");
		plotHeight = new TextBox();
		plotHeight.setWidth("50px");
		plotHeight.setText("" + Registry.getSettings().getPlotHeight());
		
		heightPanel.add(heightLbl);
		heightPanel.add(plotHeight);
		heightPanel.setSpacing(4);
		
		HorizontalPanel widthPanel = new HorizontalPanel();
		Label widthLbl = new Label("Plot Width (in pixels) : ");
		plotWidth = new TextBox();
		plotWidth.setWidth("50px");
		plotWidth.setText("" + Registry.getSettings().getPlotWidth());
		
		widthPanel.add(widthLbl);
		widthPanel.add(plotWidth);
		widthPanel.setSpacing(4);
		
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(raw);
		widgetsPanel.add(notRaw);	
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(heightPanel);
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(widthPanel);
		widgetsPanel.add(new Label(""));
		
		widgetsPanel.setSpacing(4);
		
		
		panel.setWidget(0, 0, namePanel("Plots: "));
		panel.setWidget(0, 1, widgetsPanel);					
		
		return panel;
	}
	
	private Grid thresholdSettings(){
		Grid panel = new Grid(1, 2);		
		
		VerticalPanel widgetsPanel = new VerticalPanel();
		
		Label groupsLbl = new Label("Default threshold group: ");
		groups = new ListBox();
		groups.addChangeListener(this);
		
		List items = Registry.getSettings().getThresholdGroups();
		Collections.sort(items, new ThresholdComparator());
		
		Iterator it = items.iterator();
		int index = 0;
		while(it.hasNext()){			
			Entry item = (Map.Entry)it.next();
			groups.addItem((String)item.getValue(), (String)item.getKey());
			
			if(((String)item.getKey()).equals(Registry.getSettings().getDefaultGroup()[0])){
				groups.setItemSelected(index, true);
			}
			
			index++;
		}		
		
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(groupsLbl);		
		widgetsPanel.add(new Label(""));
		widgetsPanel.add(groups);		
		widgetsPanel.add(new Label(""));
		widgetsPanel.setSpacing(4);		
		
		panel.setWidget(0, 0, namePanel("Threshold groups: "));
		panel.setWidget(0, 1, widgetsPanel);	
		
		return panel;
	}

	public void update(Object o) {	
		boolean answer = ((Boolean)o).booleanValue();
		if(answer){			
			Callback command = new Callback() {
				public void execute(Object result) {								
					progressHelper.checkProgress();
					progressHelper.initPollTimer();
				}			
			};				
			
			ServerGateway.detectSpindleIndications(
					Registry.getSettings().getDefaultGroupName(),
					Spindles.createCallBack(command));
			progressHelper.pollServer(1000);
		}
	}

	public void onClick(Widget sender) {
		if(((Button)sender).getText().equals("Cancel")){
			Spindles.get().setRightPanel(new SpindleDetectionPanel());
		} else{
			String exportPath = exportDir.getText();
			boolean showOnlyRaw = raw.isChecked();
			String groupName = groups.getValue(groups.getSelectedIndex());			
			
			final SettingsDTO dto = Registry.getSettings();
			dto.setDefaultGroupName(groupName);
			dto.setExportDirectory(exportPath);
			dto.setShowOnlyRawData(showOnlyRaw);			
			dto.setPlotHeight(Integer.parseInt(plotHeight.getText()));
			dto.setPlotWidth(Integer.parseInt(plotWidth.getText()));
			
			Registry.setSettings(dto);			
			
			Callback cmd = new Callback(){
				public void execute(Object result) {
					Spindles.showInfoDialog("Saved Changes", "Changes were saved successfully!");					
				}				
			};
			
			ServerGateway.saveSettings(dto, Spindles.createCallBack(cmd));
		}
		
	}

	public void onChange(Widget sender) {				
		String groupName = groups.getValue(groups.getSelectedIndex());		
		if(!groupName.equals(Registry.getSettings().getDefaultGroup()[0])){
			Registry.getSettings().setDefaultGroupName(groupName);
			
			QuestionDialog question = 
				new QuestionDialog("Calculate spindle indications with new thresholds ?");
			question.show();
			question.center();
			question.addSubscriber(this);
		}				
	}

	public void hideProgressBar() {
		replaceMainPanel(createMainPanel());
		
	}

	public void showProgressBar(Panel progressbar) {
		replaceMainPanel(progressbar);		
	}

}
